21. Warsztaty Reacta cz.1

Wyzwania:

  • nauczysz się tworzyć projekt reactowy od zera,
  • dowiesz się, jak zaprojektować aplikację,
  • wykorzystasz bibliotekę Material UI do obsługi warstwy wizualnej.

21.1. Wprowadzenie

Wiesz już całkiem sporo na temat Reacta! Czas uporządkować i przećwiczyć zdobyte umiejętności, a także dowiedzieć się co nieco na temat projektowania aplikacji. Przez najbliższe 2 tygodnie wideowarsztatów poznasz sporo ciekawostek, przydatnych do szybkiego uruchomienia i rozwoju nowego projektu. Oprócz tego nauczysz się też lepiej pracować z API w projektach reactowych.

Czym zatem będziemy się zajmować?

Założenia projektu

Pamiętasz jeszcze stronę pizzerii, którą stworzyliśmy w vanilla JS? Wykorzystamy ten projekt, ale nie martw się – nie będziemy go przerabiać ani rozwijać. Pozostawimy go bez zmian – możemy przyjąć, że klient wolał mieć lekką stronę opartą o vanilla JS, ale panel administracyjny będzie bardziej skomplikowany, z możliwością łatwego dodawania nowych funkcjonalności. Dlatego będziemy go realizować jako projekt reactowy, z routingiem i Reduksem.

Nasz nowy projekt będzie panelem administracyjnym pizzerii, który będzie korzystał z tego samego API, co strona zrealizowana przez nas we wcześniejszym projekcie. W ten sposób stworzymy projekt, który będzie służył do zarządzania naszą stroną – i nie tylko!

Zaimplementujesz w nim edycję produktów w menu i zarządzanie rezerwacjami, przy czym to ostatnie będzie wyświetlone w formie kalendarza godzinowego. Każdy stolik będzie miał swoją kolumnę, a wierszami będą kolejne godziny. Dzięki temu obsługa będzie mogła szybko sprawdzić, jakie rezerwacje lub wydarzenia są zaplanowane na dany dzień.

Panel administracyjny będzie miał również osobne widoki dla kelnera i dla kuchni. Kelnerzy w tej pizzerii będą mieć tablety, na których będą wprowadzać zamówienie klienta. Dzięki temu wszystkie zamówienia będą w naszym API, a kucharz będzie od razu wiedział, co musi ugotować i w jakiej kolejności ma realizować zamówienia.

W kuchni naszej restauracji będzie zamontowany telewizor, wyświetlający fragment panelu przeznaczony dla kucharza. Pozwoli to na realizację zamówień i oznaczanie statusu zamówienia. Te same statusy będzie widział kelner, który z panelu dowie się, że ma dostarczyć zamówienie do stolika.

Brzmi skomplikowanie, prawda? Nie przejmuj się! W oparciu o nasze wskazówki z tego modułu, uda Ci się zrealizować ten projekt!

Pamiętaj, że nawet bardzo skomplikowany projekt zaczyna się od prostych kroków. Za chwilę zainicjujemy środowisko projektu (w nowy sposób!) i dodamy do niego routing. Potem, krok po kroku, będziesz dodawać kolejne funkcjonalności – możesz myśleć o nich jak o mini-projektach. Każdy nowy feature wymaga specyfikacji, zaplanowania i realizacji, więc skupisz się na jednym z nich, a dopiero po jego ukończeniu na kolejnym, i kolejnym itd.

21.2. Przygotowanie środowiska z CRA

Do tej pory dostarczaliśmy Ci paczkę z początkowymi plikami projektu. Tym razem zrobimy inaczej – nauczysz się uruchamiać projekt od zera. Jak za chwilę się przekonasz, będzie to bardzo proste!

Nowe repozytorium

Stwórz nowe repozytorium o nazwie pizzeria-portal i sklonuj je. Pamiętaj, aby przy tworzeniu repozytorium nie zaznaczać opcji dotyczących plików README.md i .gitignore – potrzebujemy zupełnie pustego repozytorium.

Teraz czas na błyskawiczne zainicjowanie projektu!

Create React App

Skorzystamy z generatora projektów reactowych o nazwie Create React App (CRA), stworzonego przez Facebooka, czyli autora Reacta. Stworzy on dla nas podstawową strukturę projektu, dzięki czemu nie będziemy musieli robić tego ręcznie. Poniższe nagranie przeprowadzi Cię przez proces tworzenia projektu z wykorzystaniem CRA.

Pobierz ściągawkę CRA

Przystosowanie aplikacji do projektu

CRA pozwoliło nam szybko i łatwo zainicjować projekt reactowy. To jednak nie koniec naszej pracy na tym etapie: musimy wprowadzić nieco zmian w plikach, by pasowały one do struktury projektu, który za moment będziemy rozwijać.

Pobierz plik app.json

Pobierz plik server.js

21.3. Widoki i routing

Nasza aplikacja będzie dość złożona, więc zanim przejdziemy do kodowania, rozplanujmy sobie kilka zasadniczych kwestii.

Cykl życia zamówienia

Każde zamówienie w naszej restauracji będzie miało swój "cykl życia", czyli różne etapy, na których będzie sie znajdować. Przyjmiemy, że zamówienie będzie mogło mieć jeden z następujących statusów:

  • new – zamówienie w trakcie składania, jeszcze nie realizujemy,
  • ordered – zamówienie złożone, należy zrealizować,
  • ready – zamówienie przygotowane, należy dostarczyć,
  • in delivery – [tylko z dostawą] zamówienie w trakcie dostawy,
  • delivered – [tylko lokalne] zamówienie zostało dostarczone, ale jeszcze nie opłacone,
  • done – zamówienie zostało dostarczone i opłacone,
  • cancelled – zamówienie anulowane.

W przypadku zamówień z dostawą status ordered oznacza zamówienie opłacone, a w przypadku zamówień lokalnych – tylko złożone, ponieważ klient płaci po zjedzeniu. Dlatego status delivered będziemy stosować tylko w lokalu, a zamówienia z dostawą będą przeskakiwać od razu z in delivery na done. Analogicznie, kelner w restauracji nie będzie używał statusu in delivery, tylko zmieni status z ready na delivered.

Skoro znamy już cykl życia zamówienia, rozpiszmy sobie wszystkie widoki wedle ich adresów.

Specyfikacja widoków

Dobre zaplanowanie widoków bardzo nam pomoże wdrożyć poprawny routing w projekcie. W poniższym nagraniu zastanowimy się, czego tak naprawdę potrzebujemy w naszej aplikacji.

Uff, sporo tego! Ale nie przejmuj się – będziesz realizować widoki po kolei, a dzięki tej specyfikacji nie pogubisz się w procesie realizacji. Możesz nawet użyć narzędzia takiego jak np. Trello, aby uporządkować je sobie i móc oznaczać statusy ich wykonania.

Projektowanie aplikacji

Aby ułatwić sobie pracę nad tak złożoną aplikacją, dobrze jest rozrysować sobie (przynajmniej z grubsza), jak będą rozmieszczone na stronie poszczególne komponenty i elementy. Staranne przemyślenie, z czego ma składać się dany widok, oszczędzi Ci potem wielokrotnych poprawek i wracania do tego samego fragmentu aplikacji, żeby np. dodać kolejny button czy widget.

Od razu uprzedzamy – nie ma się czego bać ;) Nie musisz umieć projektować, ani nawet nie musisz mieć wyrobionego designerskiego oka. W zupełności wystarczy, że stworzysz wizualizację aplikacji w formie wireframe (po jednym na widok/podstronę), czyli prostego, schematycznego szkicu (prototypu), ilustrującego rozmieszczenie elementów na ekranie. Przykładowy wireframe (zupełnie innego projektu) wygląda tak:

image

Pamiętaj, że wireframes powinny być maksymalnie schematyczne i przejrzyste. Ogranicz paletę kolorystyczną (najlepiej używać tylko czerni, bieli i odcieni szarości), nie myśl o krojach czcionek czy ilustracjach. Swoje prototypy możesz z powodzeniem rozrysować na papierze, ale możesz się też posłużyć dostępnymi w internecie narzędziami, takimi jak:

Jeśli żadne z nich nie brzmi znajomo, polecamy pierwsze z nich, czyli Moqups.

Poświęć trochę energii na rozrysowanie swojej aplikacji, ale pilnuj, by nie zabrakło Ci czasu na wdrożenie projektu! Pamiętaj również, że nie musisz projektować wszystkich widoków już teraz: śmiało możesz prototypować kolejne ekrany w miarę potrzeby.

Podejście alternatywne

Niektórzy developerzy, zwłaszcza ci z większym doświadczeniem, wolą prototypować od razu w kodzie, tworząc poszczególne komponenty i dopiero potem myśląc, w jaki sposób rozłożyć je na ekranie. Możesz przetestować takie podejście i sprawdzić, czy bardziej odpowiada Ci tworzenie wizualnego mockupu przed rozpoczęciem kodowania, czy praca na żywym organizmie.

Zadanie: Uzupełnienie widoków

Mamy już specyfikację wszystkich widoków, więc czas na ich implementację! To właśnie jest Twoim zadaniem. ;)

W ramach tego zadania nie musisz jednak implementować funkcjonalności i elementów w poszczególnych widokach. Na razie wystarczy, że zaimplementujesz routing i podstawowy komponent wyświetlający tytuł widoku.

Przygotowanie do tworzenia widoków

Zacznij od dodania w src/styles/settings.scss wartości $base-size: 12px;, ponieważ za chwilę będziemy z niej korzystać.

Musimy też stworzyć komponent funkcyjny w pliku MainLayout.js w katalogu src/components/layout/MainLayout. Na razie wystarczy, że będzie renderował diva, a w nim {props.children}. W pliku App.js wykorzystaj komponent MainLayout, aby obejmował całą zawartość strony. Dzięki temu nie będziemy musieli umieszczać MainLayout z osobna w każdym z widoków.

Tworzenie komponentów widoków

Następnie dodaj komponent widoku logowania. Stwórz pliki Login.js i Login.module.scss w katalogu src/components/views/Login.

W pliku SCSS wstaw:

@import '../../../styles/settings.scss';

.component {
  padding: $base-size;
}

W pliku JS stwórz komponent funkcyjny o nazwie Login, a w jego kodzie JSX wstaw diva z klasą .component zaimportowaną z pliku SCSS, a w nim dodaj <h2> z nazwą tego widoku, czyli np. "Login view".

Następnie musimy stworzyć taki sam zestaw plików dla każdego widoku z powyższej specyfikacji. Skopiuj katalog komponentu Login i wstaw jego kopię również do src/components/views/. Wtedy zmień nazwę katalogu i plików oraz wszystkie wystąpienia słowa Login w pliku JS. W ten sposób uzyskasz kolejny komponent. Powtarzaj tę procedurę, aż powstaną wszystkie widoki.

Implementacja routingu

Wcześniej zainstalowaliśmy pakiet react-router, więc teraz czas na jego wykorzystanie w App.js. Pamiętaj, że BrowserRouter musi zawierać w sobie MainLayout, a nie odwrotnie.

Nie zapomnij też, że przy naszej konfiguracji projektu musimy uwzględnić właściwość process.env.PUBLIC_URL. Możesz to zrobić za pomocą szablonu tekstu lub połączenia dwóch tekstów znakiem +. Zobacz poniższy przykład, w którym używamy obu rozwiązań:

<BrowserRouter basename={'/panel'}>
  <MainLayout>
    <Switch>
      <Route exact path={`${process.env.PUBLIC_URL}/`} component={Homepage} />
      <Route exact path={process.env.PUBLIC_URL + '/login'} component={Login} />
    </Switch>
  </MainLayout>
</BrowserRouter>

Dodaj Route dla każdego widoku, posiłkując się specyfikacją widoków.

Menu strony

Musimy dodać jeszcze sposób nawigacji pomiędzy widokami. W katalogu src/components/layout stwórz nowy komponent funkcyjny o nazwie PageNav. Niech renderuje <nav>, a w nim linki do każdego z głównych widoków, czyli tych, które nie mają :id ani new w ścieżce.

Pamiętaj, że w linkach również musimy wykorzystywać właściwość process.env.PUBLIC_URL!

<NavLink exact to={`${process.env.PUBLIC_URL}/`} activeClassName='active'>Home</NavLink>
<NavLink to={`${process.env.PUBLIC_URL}/login`} activeClassName='active'>Login</NavLink>

Użyliśmy komponentu NavLink, aby linki dostawały klasę active, kiedy jesteśmy stronie danego widoku. Zwróć uwagę, że w powyższym przykładzie użyliśmy propsa exact tylko w linku do strony głównej – dzięki temu np. link do /ordering będzie aktywny również wtedy, kiedy będziemy znajdować się na stronie /ordering/new. To dobre podejście, kiedy chcemy w menu oznaczać dział strony, w którym znajduje się aktualnie wyświetlana strona.

Następnie, wykorzystaj komponent PageNav, dodając go do MainLayout. Dzięki temu wyświetli się na wszystkich stronach.

Linki do podstron

Ostatnią częścią zadania będzie wykorzystanie komponentu Link (a nie NavLink) do wstawienia w głównych widokach linków do ich podstron. Na przykład, widok Ordering powinien mieć linki do /ordering/new i /ordering/order/123abc.

Następnie w widokach, których ścieżki zawierają :id, wyświetl ten identyfikator pod tytułem widoku.

Podsumowanie

Mamy już przygotowane wszystkie widoki oraz działającą nawigację strony. To świetny punkt startu, ale nasza strona nie wygląda jeszcze zbyt dobrze. Musimy coś z tym zrobić...

21.4. Material Design

Do tej pory w czasie kursu zapoznaliśmy Cię z biblioteką Bootstrap, której możesz używać do szybkiego tworzenia estetycznie wyglądających stron. Bootstrap to jednak niejedyne narzędzie, które dostarcza zestawy ostylowanych komponentów. Jedną z bardziej popularnych bibliotek do tego celu jest rozwijany przez firmę Google (na podstawie licznych studiów i testów usability) Material Design, który skupia się na prostocie, czytelności i zaznaczaniu wizualnej hierarchii elementów.

Oczywiście moglibyśmy napisać od podstaw style dla wszystkich komponentów, ale użycie biblioteki znacznie usprawni nam pracę. Będziemy mieć także pewność, że nasza aplikacja będzie estetyczna, spójna i użyteczna (np. kolory będą miały odpowiedni kontrast, a teksty czytelną wielkość czcionki). Warto poza tym wspomnieć, że Material Design jest dostosowany zarówno do urządzań desktopowych, jak i mobilnych.

image

Biblioteka Material Design została dostosowana do Reacta w postaci pakietu Material UI. Dostarcza on gotowe, ostylowane komponenty reactowe, których z łatwością możesz użyć w swoim projekcie.

image

Dokumentacja komponentów Material UI zawiera wiele przykładów i gotowych fragmentów kodu – na tym etapie raczej nie będziesz mieć problemów ze zrozumieniem, jak one działają. :)

Pierwsza implementacja Material-UI może jednak sprawiać nieco problemów, ze względu na jej domyślne zachowanie. Dlatego zajmiemy się tym wspólnie w poniższym nagraniu.

Tworzenie widoków

Zacznij samodzielnie budować zaplanowane przez nas widoki, wykorzystując komponenty z Material UI. Na tym etapie możesz w nich wstawiać przykładową treść, wpisując ją bezpośrednio w kodzie JSX.

Na razie skup się wyłącznie na tym, aby w poszczególnych widokach znalazły się wszystkie zaplanowane elementy strony.

W następnym module pokażemy Ci ciekawsze podejście do umieszczania przykładowych treści w tworzonych komponentach, a także zajmiemy się podłączeniem widoków pod Reduksa.

;